// 
//   Copyright © 2009 Jiří Zárevúcky <zarevucky.jiri@gmail.com>
//  
//   This program is free software: you can redistribute it and/or modify
//   it under the terms of the GNU Affero General Public License as
//   published by the Free Software Foundation, either version 3 of the
//   License, or (at your option) any later version.
//  
//   This program is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   GNU Affero General Public License for more details.
//  
//   You should have received a copy of the GNU Affero General Public License
//   along with this program.  If not, see <http://www.gnu.org/licenses/>.
//  
//  


using System;
using System.IO;
using System.Threading;
using System.Collections.Generic;
using Galaxium.Protocol.Xmpp.Library.Xml;
using Galaxium.Protocol.Xmpp.Library.Core;

using Anculus.Core;

namespace Galaxium.Protocol.Xmpp.Library.Streams
{
	public class FileTransferListener: IStreamProfileListener
	{
		public event EventHandler<FileTransferEventArgs> TransferRequested;
		
		string IStreamProfileListener.ProfileNamespace {
			get { return Namespaces.SIFileTransfer; }
		}
		
		public string DefaultPath { get; set; }
		
		
		RequestResult IStreamProfileListener.HandleRequest (JabberID uid, string sid, string mime_type,
		                                                    IEnumerable<string> methods, Element data)
		{
			long size;
			string name/*, hash*/;
		//	DateTime date;
			bool supports_offset;
			string description;
			try {
				size = Int64.Parse (data ["size"]);
				name = data ["name"];
			//	var date_str = data ["date"];
			//	if (date_str != null)
			//		date = DateTime.Parse (date_str);
			//	hash = data ["hash"];
				supports_offset = data.FirstChild ("range", null) != null;
				var desc_elm = data.FirstChild ("desc", null);
				description = desc_elm == null ? null : desc_elm.Text;
			}
			catch {
				throw new QueryException ("modify", "bad-request", null);
			}

			var wait_handle = new ManualResetEvent (false);
			if (TransferRequested == null)
				return new RequestResult (false, "No filetransfer handler registered.", null, null, null);
			var transfer = new FileTransfer (uid, sid, name, size, description, wait_handle);
			TransferRequested (this, new FileTransferEventArgs (transfer));
			wait_handle.WaitOne ();
			
			if (!transfer.IsAccepted)
				return new RequestResult (false, transfer.DeclineReason, null, null, null);
			
			var reply_data = new Element ("file", Namespaces.SIFileTransfer);
			
			var path = transfer.FilePath + ".part" ?? Path.Combine (DefaultPath, name + ".part");
			if (supports_offset && File.Exists (path)) {
				var range = new Element ("range");
				range ["offset"] = GetFileSize (path).ToString ();
				reply_data.AppendChild (range);
			}
			
			Log.Info ("Accepting file. Name = " + name + ", size = " + size.ToString ());
			
			return new RequestResult (true, null, Namespaces.Socks5Bytestream, reply_data,
			                          (r, s) => transfer.HandleStream (r, s, path, supports_offset));
		}
		
		private long GetFileSize (string path)
		{
			FileStream file = null;
			try {
				file = File.OpenRead (path);
				return file.Length;
			}
			finally {
				if (file != null)
					file.Close ();
			}
		}
	}
}
